package main

import (
	"fmt"
	"os"
)

type User struct {
	name string
	age  int
}

func chvalue(a int) int {
	a = a + 1
	return a
}

func chpointer(a *int) {
	*a = *a + 1
	return
}
func add(a, b int) int {
	return a + b
}

// 定义一个函数类型
type Op func(int, int) int

func do(f Op, a, b int) int {
	return f(a, b)
}

// 匿名函数直接赋值给变量
var sum = func(a, b int) int {
	return a + b
}

func doinput(f func(int, int) int, a, b int) int {
	return f(a, b)
}

// 匿名函数作为返回值
func wrap(op string) func(int, int) int {
	switch op {
	case "add":
		return func(x int, y int) int {
			return x + y
		}
	case "sub":
		return func(x int, y int) int {
			return x - y
		}
	default:
		return nil
	}
}

func f() int {
	a := 0
	defer func(i int) {
		print("defer i=", i)
	}(a)
	a++
	return a
}

//defer 示例
//func CopyFile(dst, src string) (w int64, err error) {
//	src, err := os.Open(src)
//	if err != nil {
//		return
//	}
//
//	defer src.Close()
//
//	dst, err := os.Create(dst)
//	if err != nil {
//		return
//	}
//
//	defer src.Close()
//
//	w, err = io.Copy(dst, src)
//
//	return
//
//}

func main() {
	// 2。函数
	a := 10
	chvalue(a)
	fmt.Println(a)

	chpointer(&a)
	fmt.Println(a)

	// 2.2.1 函数签名
	fmt.Printf("%T\n", add)

	// 2.2.1-1
	b := do(add, 1, 2)
	fmt.Println(b)

	// 2.2.2 匿名函数
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	sum(1, 2)

	// 匿名函数作为实参
	doinput(func(x int, y int) int {
		return x + y
	}, 1, 2)

	opFunc := wrap("add")
	re := opFunc(2, 3)
	fmt.Printf("%T", opFunc)
	fmt.Println(re)

	//defer 可以注册多个延迟调用，以先进后出（FIFO）的顺序在函数返回前被执行
	//defer 常用于保证一些资源最终一定能够得到回收和释放
	defer func() {
		fmt.Println("first, time")
	}()
	defer func() {
		fmt.Println("second, time")
	}()
	println("function body")
	//以上输出
	//function body
	//second, time
	//first, time
	//
	//主动调用
	os.Exit(1)
	//function body

	//defer 后面不可以是语句，否则报错：expression in defer must be function call
	//defer "HelloWorld"

	return
	// defer 位于 return 之后，不会执行
	defer func() {
		print("Hello")
	}()

	// 2.5 panic 和 recover
	// 不捕获
	defer recover()
	// 不捕获
	defer fmt.Println(recover())
	// 不捕获
	defer func() {
		func() {
			println("defer inner")
			recover()
		}()
	}()
}
